/* WiFi station Example

   This example code is in the Public Domain (or CC0 licensed, at your option.)

   Unless required by applicable law or agreed to in writing, this
   software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
   CONDITIONS OF ANY KIND, either express or implied.
*/
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/projdefs.h"
#include "freertos/task.h"
#include "freertos/event_groups.h"
#include "esp_system.h"
#include "esp_wifi.h"
#include "esp_event.h"
#include "esp_log.h"
#include "nvs_flash.h"

#include "lwip/err.h"
#include "lwip/sys.h"


#include "my_wifi.h"


#define EXAMPLE_ESP_MAXIMUM_RETRY  5
 

/* The event group allows multiple bits for each event, but we only care about two events:
 * - we are connected to the AP with an IP
 * - we failed to connect after the maximum amount of retries */


//wifi ssid pswd len  不能超过32和64
#define SSID_LEN 32
#define PSWD_LEN 64

//wifi nvs
#define SSID_KEY "wifi_ssid"
#define PSWD_KEY "wifi_pswd"



#define ALL_BITS (0x0f)

static const char *TAG = "wifi";

static int wifi_init_finished = 0;
/* FreeRTOS event group to signal when we are connected*/
static EventGroupHandle_t s_wifi_event_group;

wifi_config_t wifi_config = {
    .sta = {
        // .ssid = {'4','0','2',,'p','u','b','l','i','c'},
        .ssid = "WENBENTEC",
        .password = "00000000",
        /* Setting a password implies station will connect to all security modes including WEP/WPA.
            * However these modes are deprecated and not advisable to be used. Incase your Access point
            * doesn't support WPA2, these mode can be enabled by commenting below line */
        .threshold.authmode = WIFI_AUTH_WPA2_PSK,
        .pmf_cfg = {
            .capable = true,
            .required = false
        },
    },
};

uint8_t wifi_is_inited(void) {
    return wifi_init_finished;
}

void set_wifi_state(wifi_state_t state) {
    // 0x0f = 1111
    xEventGroupClearBits(s_wifi_event_group, ALL_BITS);
    xEventGroupSetBits(s_wifi_event_group, _BIT(state));
}

wifi_state_t get_wifi_state(void) {
    EventBits_t bits = xEventGroupGetBits(s_wifi_event_group);
    if (bits != _BIT(nostart_wifi) || 
        bits != _BIT(connect_failed_wifi) || 
        bits != _BIT(connecting_wifi) || 
        bits != _BIT(connect_success_wifi)) {
       return -1; 
    }
    return (wifi_state_t)bits;
}


static void event_handler(void* arg, esp_event_base_t event_base,
                                int32_t event_id, void* event_data)
{
    if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START) {
        set_wifi_state(connecting_wifi);
        esp_wifi_connect();
    } else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED) {
        ESP_LOGI(TAG,"connect to the AP fail");
        set_wifi_state(connect_failed_wifi);
        esp_wifi_stop();
    } else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) {
        ip_event_got_ip_t* event = (ip_event_got_ip_t*) event_data;
        ESP_LOGI(TAG, "got ip:" IPSTR, IP2STR(&event->ip_info.ip));
        set_wifi_state(connect_success_wifi);
    }
}


uint8_t wifi_init(void)
{
    s_wifi_event_group = xEventGroupCreate();
    set_wifi_state(nostart_wifi);
    ESP_ERROR_CHECK(esp_netif_init());
    ESP_ERROR_CHECK(esp_event_loop_create_default());

    esp_netif_create_default_wifi_sta();

    wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
    ESP_ERROR_CHECK(esp_wifi_init(&cfg));

    ESP_ERROR_CHECK(esp_event_handler_register(WIFI_EVENT, ESP_EVENT_ANY_ID, &event_handler, NULL));
    ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT, IP_EVENT_STA_GOT_IP, &event_handler, NULL));
    /* Waiting until either the connection is established (WIFI_CONNECTED_BIT) or connection failed for the maximum
     * number of re-tries (WIFI_FAIL_BIT). The bits are set by event_handler() (see above) */ 
    ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA) );  
    vTaskDelay(pdMS_TO_TICKS(2000));
    wifi_init_finished = 1;
    return 0;
}

void start_sta_wifi(void){

    ESP_ERROR_CHECK(esp_wifi_set_config(ESP_IF_WIFI_STA, &wifi_config));
    ESP_ERROR_CHECK(esp_wifi_start()); 
    ESP_LOGI(TAG, "esp_wifi_start.");
}

wifi_state_t wifi_wait_result(uint32_t wait_bits,  uint32_t overtime) {
    // ESP_LOGI(TAG, "waitting wifi group bits"); 
    EventBits_t bits = 0;
    wifi_state_t res = 0xff;
    bits = xEventGroupWaitBits(s_wifi_event_group, wait_bits,
            pdFALSE, pdFALSE, overtime);   
    if(bits == _BIT(connect_success_wifi)){
        res = connect_success_wifi;
    }else if (bits == _BIT(connecting_wifi))
    {    
        res = connect_failed_wifi;
    }else if (bits == _BIT(connect_failed_wifi))
    {    
        res = connect_failed_wifi;
    }else if (bits == _BIT(nostart_wifi))
    {    
        res = nostart_wifi;
    }else {
        ESP_LOGE(TAG, "UNEXPECTED EVENT");
        return 0xff;
    }
    return res;
}




void modify_wificonfig_pswd(const char* pswd){
    //len of pswd <PSWD_LEN
    strcpy((char*)wifi_config.sta.password, (const char *)pswd);  
    printf("\n pswd  is %s \n",wifi_config.sta.password);     
}

void modify_wificonfig_ssid(const char* ssid){
    //len of pswd <SSID_LEN
    printf("\n get data is %s \n",ssid);
    strcpy((char*)wifi_config.sta.ssid, (const char *)ssid); 
    printf("\n ssid  is %s \n",wifi_config.sta.ssid);   
}

esp_err_t store_wificonfig_to_nvs(void){
    uint8_t ssid[SSID_LEN] = {0};
    uint8_t pswd[PSWD_LEN] = {0};
    strcpy((char*)ssid, (const char *)wifi_config.sta.ssid);
    strcpy((char*)pswd, (const char *)wifi_config.sta.password);

    nvs_handle wifiNvsHandle;
    esp_err_t err;

    err = nvs_open("wifi_config", NVS_READWRITE, &wifiNvsHandle);
    if (err != ESP_OK) {
        printf("Error (%s) opening NVS handle!\n", esp_err_to_name(err));
        return err;
    }
    nvs_set_str(wifiNvsHandle, SSID_KEY, (const char *)ssid);
    nvs_set_str(wifiNvsHandle, PSWD_KEY, (const char *)pswd);
    nvs_commit(wifiNvsHandle);
    nvs_close(wifiNvsHandle);
    return ESP_OK;
}

esp_err_t set_wifi_config_from_nvs(void){
    uint8_t ssid[SSID_LEN] = {0};
    uint8_t pswd[PSWD_LEN] = {0};
    uint8_t ssid_len = SSID_LEN;
    uint8_t pswd_len = PSWD_LEN;
    nvs_handle wifiNvsHandle;

    esp_err_t err;

    err = nvs_open("wifi_config", NVS_READWRITE, &wifiNvsHandle);
    if (err != ESP_OK) {
        printf("Error (%s) opening NVS handle!\n", esp_err_to_name(err));
        return err;
    }

    err = nvs_get_str(wifiNvsHandle, SSID_KEY, (char*)ssid, &ssid_len);
    if (err != ESP_OK) {
        printf("get ssid failed, err(%s)\n", esp_err_to_name(err));
        return err;
    }
    printf("get ssid = %s \n",ssid);
    err = nvs_get_str(wifiNvsHandle, PSWD_KEY, (char*)pswd, &pswd_len);
    if (err != ESP_OK) {
        printf("get pswd failed, err(%s)\n", esp_err_to_name(err));
        return err;
    }
    printf("get pswd = %s \n",pswd); 
    
    strcpy((char*)wifi_config.sta.ssid, (const char *)ssid);
    strcpy((char*)wifi_config.sta.password, (const char *)pswd);

    ESP_LOGI(TAG, " SSID:%s, \n password:%s \n",
                 wifi_config.sta.ssid, wifi_config.sta.password);  

    nvs_commit(wifiNvsHandle);
    nvs_close(wifiNvsHandle);
    return ESP_OK;
}
